﻿using System.ComponentModel;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using HiSport.Core.Entity.Bas;
using HiSport.Core.Enum;
using HiSport.Core.Util;
using HiSportApplet.Application.Common.SqlSugar;
using HiSportApplet.Application.Service.Function.ReserveSiteManagement.Service;
using HiSportApplet.Application.Service.Order.OrderSiteManagement.Dtos;
using HiSportApplet.Core.Entity.Bas;
using HiSportApplet.Core.Entity.Orders;
using HiSportApplet.Core.Enum;
using HiSportApplet.Core.Util;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Yitter.IdGenerator;

namespace HiSportApplet.Application.Service.Order.OrderSiteManagement
{

    [ApiDescriptionSettings("订单管理", Tag = "订场订单管理", SplitCamelCase = false)]
    public class OrderSiteService : ITransient, IOrderSiteService, IDynamicApiController
    {

        private readonly SqlSugarRepository<OrderSite> _order;
        private readonly SqlSugarRepository<OrderSiteInfo> _orderInfo;
        private readonly IScheduledSiteService _reserveSiteService;
        private readonly SqlSugarRepository<BasVenues> _basVenuesRep;
        private readonly SqlSugarRepository<BasSiteType> _basSiteTypeRep;
        private readonly SqlSugarRepository<BasVenuesEventsType> _basVenuesEventsType;
        private readonly SqlSugarRepository<BasVenuesImage> _venuesImageRep;
        private readonly SqlSugarRepository<BasSiteBillingRule> _basSiteBillingRule;
        private readonly SqlSugarRepository<BasBillingRule> _basBillingRule;
        private readonly SqlSugarRepository<BasBillingRuleInfo> _basBillingRuleInfo;

        public OrderSiteService
            (SqlSugarRepository<OrderSite> orderInfo,
            SqlSugarRepository<OrderSiteInfo> orderSiteInfo,
            IScheduledSiteService reserveSiteService,
            SqlSugarRepository<BasSiteBillingRule> basSiteBillingRule,
            SqlSugarRepository<BasBillingRule> basBillingRule,
            SqlSugarRepository<BasBillingRuleInfo> billingRuleInfo,
            SqlSugarRepository<BasSiteType> basSiteType,
            SqlSugarRepository<BasVenues> basVenuesRep,
            SqlSugarRepository<BasVenuesImage> venuesImageRep
            )
        {
            _order = orderInfo;
            _orderInfo = orderSiteInfo;
            _reserveSiteService = reserveSiteService;
            _basSiteBillingRule = basSiteBillingRule;
            _basBillingRule = basBillingRule;
            _basBillingRuleInfo = billingRuleInfo;
            _basSiteTypeRep = basSiteType;
            _basVenuesRep = basVenuesRep;
            _venuesImageRep = venuesImageRep;
        }



        /// <summary>
        /// 分页获取订场订单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [ApiDescriptionSettings(Name = "Page"), HttpPost]
        [DisplayName("分页获取订场订单")]
        public async Task<SqlSugarPagedList<OrderSiteDto>> Page(OrderSitePageInputDto input)
        {

            ParamNull(input);

            #region 必填验证
            var sysMemberId = input.SysMemberId;//平台会员
            if (sysMemberId <= 0)
            {
                throw Oops.Oh("会员信息必填");
            }
            #endregion

            #region 查询条件

            var data = _order.AsQueryable();

            #region 系统会员ID

            data = data.Where(a => a.MemberId == sysMemberId);

            #endregion

            #region 订单来源

            var orderSource = input.OrderSource;
            if (orderSource != null && orderSource.HasValue)
            {
                data = data.Where(a => a.OrderSource == orderSource.Value);
            }

            #endregion

            #region 查询状态 

            var searchType = input.SearchType;
            if (searchType != null && searchType.HasValue && searchType.Value != 0)
            {
                //TODO:过期的订单属于什么  已取消还是已过期

                #region 1-待付款：
                if (searchType.Value == SearchTypeEnum.Unpaid)
                {
                    //待付款  /*待支付：支付状态=未支付或者部分支付的(不等于全部付款的部分)*/
                    data = data.Where(a => a.OrderPayState != OrderPayStateEnum.AllPayment);

                }
                #endregion

                #region 2-待使用：
                else if (searchType.Value == SearchTypeEnum.NotUsed)
                {

                    /*待使用*/
                    data = data.Where(a => a.OrderPayState != OrderPayStateEnum.AllPayment);

                    //TODO:待使用
                }
                #endregion

                #region 3-使用中：
                else if (searchType.Value == SearchTypeEnum.Using)
                {

                    data = data.Where(a => a.OrderState == OrderStateEnum.Afoot);

                }
                #endregion

                #region 4-已完成：
                else if (searchType.Value == SearchTypeEnum.Completed)
                {

                    data = data.Where(a => a.OrderState == OrderStateEnum.Complete);

                }
                #endregion

                #region 5-已取消：
                else if (searchType.Value == SearchTypeEnum.Cancelled)
                {

                    data = data.Where(a => a.OrderState == OrderStateEnum.AllCancel);

                }
                #endregion 



            }

            #endregion

            #endregion


            #region 排序+ 分页(订单的创建时间先后顺序)

            var result = await data.OrderBy(u => u.CreateTime, OrderByType.Desc)
                .Select(u => new OrderSiteDto()
                {
                    Id = u.Id.SelectAll(),
                })
                .ToPagedListAsync(input.Page, input.PageSize);
            if (result == null || result.Items == null || !result.Items.Any()) return new SqlSugarPagedList<OrderSiteDto>();

            #endregion

            #region 返回场馆信息

            SearchBillDtlPrivate(result.Items.ToList(), input.IsSearchVenues, input.IsSearchImage, input.IsSearchDtl);


            #endregion


            return result;
        }



        /// <summary>
        /// 某个订单详情
        /// </summary>
        /// <param name="input">输入参数</param>
        /// <returns></returns>
        [ApiDescriptionSettings(Name = "SearchOrderDetails"), HttpPost]
        [DisplayName("某个订单详情")]
        public async Task<OrderSiteDto> SearchOrderDetails(SearchOrderDetailsInputDto input)
        {

            #region 必填验证

            ParamNull(input);
            if (input.BillId <= 0)
            {
                throw Oops.Oh("订单信息必填");
            }

            var sysMemberId = input.SysMemberId;//平台会员
            if (sysMemberId <= 0)
            {
                throw Oops.Oh("会员信息必填");
            }

            #endregion



            var data = await _order.GetFirstAsync(a => a.Id == input.BillId && a.MemberId == input.SysMemberId);
            if (data == null) throw Oops.Oh("不存在此订单");

            var item = data.Adapt<OrderSiteDto>();

            // 返回场馆信息

            SearchBillDtlPrivate(new List<OrderSiteDto> { item }, input.IsSearchVenues, input.IsSearchImage, input.IsSearchDtl);

            return item;
        }


        /// <summary>
        /// 查询订单详情私有方法
        /// </summary>
        /// <param name="item"></param>
        /// <param name="isSearchVenues">是否查询场馆信息</param>
        /// <param name="isSearchImage">是否查询场馆图片</param>
        /// <param name="isSearchDtl">是否查询订单明细</param>
        /// <returns></returns>
        private void SearchBillDtlPrivate(List<OrderSiteDto> item, bool isSearchVenues, bool isSearchImage, bool isSearchDtl)
        {

            if (item == null || !item.Any()) return;
            var venuesIds = item.Select(a => a.VenuesId).Distinct().ToList();
            var venues = new List<BasVenuesDto>();
            if (isSearchVenues)
            {
                venues = _basVenuesRep.AsQueryable().Where(a => venuesIds.Contains(a.Id)).ToList().Adapt<List<BasVenuesDto>>();
            }
            //场地类型：
            var siteTypeIds = item.Select(a => a.SiteTypeId).Distinct().ToList();
            var siteTypeData = _basSiteTypeRep.AsQueryable()
                 .InnerJoin<BasSportsEventsType>((a, b) => a.SportsEventsTypeCode == b.SportsEventsCode)
                 .Where((a, b) => b.IsDelete == false && siteTypeIds.Contains(a.Id))
                 .Select((a, b) => new { SitypeId = a.Id, a.SiteTypeName, b.SportsEventsName, a.SportsEventsTypeCode })
                 .ToList();

            //场地的图片
            var images = new List<BasVenuesImage>();
            if (isSearchImage)
            {
                images = _venuesImageRep.AsQueryable().Where(a => venuesIds.Contains(a.VenuesId)).ToList();
            }

            //订单明细：
            var orderInfos = new List<OrderSiteInfoDto>();
            if (isSearchDtl)
            {
                var orderSiteIds = item.Select(a => a.Id).Distinct().ToList();
                orderInfos = _orderInfo.AsQueryable()
                   .InnerJoin<BasSite>((a, b) => a.SiteId == b.Id)
                   .Where(a => a.IsDelete == false && orderSiteIds.Contains(a.OrderSiteId))
                   .Select((a, b) => new OrderSiteInfoDto
                   {
                       Id = a.Id.SelectAll(),
                       SiteName = b.SiteName
                   }).ToList();
            }

            foreach (var i in item)
            {
                //场地
                var venuesId = i.VenuesId;
                if (isSearchVenues)
                {
                    var venue = venues.FirstOrDefault(a => a.Id == venuesId);
                    i.BasVenues = venue;
                }
                //场地类型
                var siteType = siteTypeData.FirstOrDefault(a => a.SitypeId == i.SiteTypeId);
                i.SiteTypeName = siteType == null ? string.Empty : siteType.SiteTypeName;

                //运动项目类型编码
                i.SportsEventsName = siteType == null ? string.Empty : siteType.SportsEventsName;
                i.SportsEventsTypeCode = siteType == null ? string.Empty : siteType.SportsEventsTypeCode;

                //场馆图片
                if (isSearchImage)
                {
                    var image = images.Where(a => a.VenuesId == venuesId).Select(a => a.Image).ToList();
                    i.ImageList = new List<string>();
                    i.ImageList = image;
                }

                //订单明细
                if (isSearchDtl)
                {
                    var orderInfo = orderInfos.Where(a => a.OrderSiteId == i.Id).ToList();
                    i.Dtls = new List<OrderSiteInfoDto>();
                    i.Dtls = orderInfo;
                }
            }
        }

        /// <summary>
        /// 参数为NULL验证
        /// </summary>
        /// <param name="input"></param>
        private void ParamNull(object input)
        {
            if (input == null) throw Oops.Oh("参数错误:参数为NULL");
        }


        /// <summary>
        /// 创建订场订单
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [UnitOfWork]
        [ApiDescriptionSettings(Name = "Create"), HttpPost]
        [DisplayName("创建订场订单")]
        public async Task<long> Create(OrderSiteCreateDto inputDto)
        {
            //1.创建主订单
            var orderData = inputDto.Adapt<OrderSite>();
            orderData.OrderNum = FunctionUtil.GetOrderNum(OrderNumType.DC);
            orderData.OrderSource = inputDto.OrderSource.HasValue ? OrderSourceEnum.Background : orderData.OrderSource;

            //重新计算订单价格，忽略前端传的
            var price = await GetOrderPrice(inputDto.OrderSiteInfos, inputDto.MemberId > 0);
            orderData.ActualPayAmount = 0;
            orderData.PayableAmount = price.payableAmount;
            orderData.TotalAmount = price.totalAmount;
            orderData.DiscountAmount = orderData.TotalAmount - orderData.PayableAmount;


            orderData.Id = YitIdHelper.NextId();
            await _order.InsertAsync(orderData);

            //2.创建子订单
            var orderInfoData = new List<OrderSiteInfo>();
            foreach (var item in inputDto.OrderSiteInfos)
            {
                var info = price.priceInfo.Where(x => x.Key == item);
                orderInfoData.Add(new OrderSiteInfo()
                {
                    StartTime = item.StartTime,
                    EndTime = item.EndTime,
                    OrderSiteId = orderData.Id,
                    SiteId = item.SiteId,
                    SiteTypeId = item.SiteTypeId,
                    ScheduledSiteState = ScheduledSiteStateEnum.OfflineUnpaid,
                    ScheduledTime = inputDto.ScheduledTime.Date,
                    ActualPayAmount = inputDto.MemberId > 0 ? info.First().Value.priceVip : info.First().Value.price,
                    OriginalPrice = info.First().Value.price
                });
            }

            //验证场地是否可以预定
            await _reserveSiteService.SiteCheck(orderInfoData.Select(x => new SiteCheckDto()
            {
                EndTime = x.EndTime,
                SiteId = x.SiteId,
                StartTime = x.StartTime,
                Time = x.ScheduledTime
            }).ToList());

            await _orderInfo.InsertRangeAsync(orderInfoData.ToArray());

            return orderData.Id;
        }


        /// <summary>
        /// 获取订单价格  
        /// </summary>
        /// <returns></returns>
        private async Task<(decimal totalAmount, decimal payableAmount, Dictionary<OrderSiteInfoCreateDto, (decimal price, decimal priceVip)> priceInfo)> GetOrderPrice(List<OrderSiteInfoCreateDto> inputDto, bool isMember)
        {
            var totalAmount = new decimal(0);
            var payableAmount = new decimal(0);
            var priceInfo = new Dictionary<OrderSiteInfoCreateDto, (decimal price, decimal priceVip)>();


            //所有场地
            var siteIdList = inputDto.Select(x => x.SiteId).Distinct().ToList();

            //查询场地配置的计费规则
            var billingRule = await _basSiteBillingRule.AsQueryable()
                .Where(x => siteIdList.Contains(x.SiteId) && x.Status == StatusEnum.Enable)
                .OrderBy(x => x.Sort)
                .ToListAsync();

            var billingRuleId = billingRule.Select(x => x.BillingRuleId).ToList();

            //查询接规则
            billingRuleId = await _basBillingRule.AsQueryable()
                .Where(x => billingRuleId.Contains(x.Id) && x.Status == StatusEnum.Enable)
                .Select(x => x.Id)
                .ToListAsync();

            //查询计费规则详情
            var billingRuleInfoList = await _basBillingRuleInfo.AsQueryable()
                .Where(x => billingRuleId.Contains(x.BillingRuleId)).ToListAsync();

            foreach (var item in inputDto)
            {
                //场地的计费规则
                var v1 = billingRule.Where(x => x.SiteId == item.SiteId).ToList();
                //场地的计费规则主id
                var vid = billingRule.Select(x => x.BillingRuleId).ToList();
                //计费规则详情
                var v2 = billingRuleInfoList.Where(x => vid.Contains(x.BillingRuleId)).ToList();

                var price = await GetSitePrice(v1, v2, item.StartTime, item.EndTime);
                totalAmount += price.price;
                if (isMember)
                {
                    payableAmount += price.unifyPriceVip;
                }
                else
                {
                    payableAmount += price.price;
                }

                priceInfo.Add(item, (price.price, price.unifyPriceVip));
            }
            return (totalAmount, payableAmount, priceInfo);
        }

        /// <summary>
        /// 获取价格
        /// </summary>
        /// <param name="billingRule"></param>
        /// <param name="billingRuleInfoList"></param>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        private async Task<(decimal price, decimal unifyPriceVip, Dictionary<long, decimal> priceVip)> GetSitePrice(List<BasSiteBillingRule> billingRule, List<BasBillingRuleInfo> billingRuleInfoList, string startTime, string endTime)
        {
            //普通价格
            var price = new decimal(0);

            //同意VIP价格
            var unifyPriceVip = new decimal(0);

            //VIP详细价格
            var priceVip = new Dictionary<long, decimal>();


            foreach (var item in billingRule)
            {
                var infoList = billingRuleInfoList.Where(x => x.BillingRuleId == item.BillingRuleId);
                foreach (var info in infoList)
                {

                    var infoStartTime = Convert.ToDateTime(info.StartTime.ToString() + ":00");
                    var infoEndTime = Convert.ToDateTime("00:00");
                    if (info.EndTime == 24)
                    {
                        infoEndTime = Convert.ToDateTime("23:59");
                    }

                    //时间段类 符合的价格
                    if (Convert.ToDateTime(startTime) >= infoStartTime)
                    {
                        if (Convert.ToDateTime(endTime) <= infoEndTime)
                        {
                            price = info.Price;
                            unifyPriceVip = info.MemberPriceType == MemberPriceTypeEnum.Unify ? info.MemberUnifyPrice : 0;
                            priceVip.Add(0, 0);
                            return (price, unifyPriceVip, priceVip);
                        }
                    }
                }

            }

            return (price, unifyPriceVip, priceVip);
        }
    }
}
